<!DOCTYPE html>
<html lang="zh">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <title>SEVEN-IM</title>
    <link rel="shortcut icon" href="images/favicon.ico" type="image/x-icon"/>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vant@2.9/lib/index.css"/>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vant@2.9/lib/vant.min.js"></script>
    <script src="https://cdn.bootcss.com/moment.js/2.24.0/moment.min.js"></script>
    <script src="https://cdn.bootcss.com/lodash.js/4.17.15/lodash.core.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.19.2/axios.min.js"></script>
    <style>
        html, body {
            padding: 0px;
            margin: 0px;
            width: 100%;
            height: 100%;
        }

        .message {
            display: flex;
            flex-direction: row;
            margin: 12px 0px;
        }

        .message-self {
            justify-content: flex-end;
        }

        .message-other {
            justify-content: flex-start;
        }

        .message .name {
            font-size: 12px;
            color: #999;
        }

        .text {
            padding: 8px 12px;
            background: deepskyblue;
            color: white;
            border-radius: 6px;
            margin-top: 6px;
            max-width: calc(100% - 80px);
            font-size: 12px;
            letter-spacing: .5px;
            word-break: break-all;
        }

        .text-other {
            background: lightcyan;
            color: darkslategrey;
        }

        .time-text {
            color: #ccc;
            margin: 0 14px;
        }

        .content {
            flex: 1 0 auto;
            display: flex;
            flex-direction: column;
        }

        .content-other {
            justify-content: flex-start;
            align-items: flex-start;
        }

        .content-self {
            justify-content: flex-end;
            align-items: flex-end;
        }

        .emoji-container {
            padding: 6px;
            font-size: 15px;
            background: #f1f1f1;
            display: flex;
            flex-flow: row wrap;
        }

        .emoji {
            margin: 6px;
            cursor: pointer;
        }


        #chat_dialog::-webkit-scrollbar {
            width: 0px
        }

    </style>
</head>
<body>
<div id="app" style="width: 100%;height: 100%;">
    <div style="display: flex;flex-direction: column;justify-content: space-between;height: 100%;">
        <div style="flex:1 0 auto;display: flex;flex-direction: column;justify-content: start;">
            <van-nav-bar style="flex:0 0 auto" title="SEVEN-IM" :right-text="rightText"
                         @click-left="onClickLeft" @click-right="onClickRight">
                <template #left>
                    <van-icon name="friends-o" size="18"/>
                </template>
            </van-nav-bar>
            <div id="chat_dialog" style="flex:1 0 auto;padding: 8px;overflow: auto;"
                 v-bind:style="{ height: contentHeight}" @click="hideEmoji">
                <template v-for="m of messages">
                    <template v-if="m.type=='TYPE_SYSTEM'">
                        <div style="text-align:center;color:#aca;margin:4px auto;font-size: 12px;">{{m.content}}</div>
                    </template>
                    <template v-if="m.type!='TYPE_SYSTEM'">
                        <div v-if="m.fromId==myself.id" class="message message-self">
                            <div class="content content-self">
                                <div class="name"><span class="time-text">{{m.sendTime}}</span> {{m.fromName}}</div>
                                <div class="text" v-html="m.content"></div>
                            </div>
                            <van-image round width="32px" height="32px" :src="'images/'+m.fromAvatar"
                                       style="margin-left: 12px;"></van-image>
                        </div>
                        <div v-if="m.fromId!=myself.id" class="message message-other">
                            <van-image round width="32px" height="32px" :src="'images/'+m.fromAvatar"
                                       style="margin-right: 12px;"></van-image>
                            <div class="content content-other">
                                <div class="name">{{m.fromName}} <span class="time-text">{{m.sendTime}}</span></div>
                                <div class="text text-other" v-html="m.content"></div>
                            </div>
                        </div>
                    </template>
                </template>
            </div>
            <div style="flex:0 0 50px;display: flex;justify-content: space-between;align-items: center;padding:0px 12px 6px;border-top: 1px solid #f4f7fb;">
                <div style="flex:0 0 auto;">
                    <van-icon name="smile-o" size="24" @click="showEmoji"/>
                    <van-icon name="photo-o" size="24" @click="uploadImg" style="margin-left: 14px;"/>
                    <form id="imgForm" style="display: none;">
                        <input id="imgFile" type="file" accept="image/jpeg, image/gif, image/png" @change="imgChange">
                    </form>
                </div>
                <div style="flex:1 0 auto;" @click="hideEmoji">
                    <van-field v-model="sendText" v-on:keyup.enter="sendMsg"
                               style="border-bottom: 1px solid #f4f7fb;margin:0px 14px;width: unset !important;"/>
                </div>
                <div style="flex:0 0 auto;" @click="hideEmoji">
                    <van-button type="primary" size="small" @click="sendMsg">发送</van-button>
                </div>
            </div>
        </div>

        <div v-if="emojiVisible" style="flex:0 0 100px;overflow: auto;">
            <div class="emoji-container">
                <div v-for="e of emoji" class="emoji" :title="e.title" @click="chooseEmoji(e.value)">{{e.value}}</div>
            </div>
        </div>

        <van-dialog v-model="registerVisible" title="请输入个名字吧~" show-confirm-button="false" @confirm="register">
            <van-field v-model="registerName" autofocus placeholder="名字"></van-field>
        </van-dialog>
    </div>
</div>
</body>
<script>

    const app = new Vue({
        el: '#app',
        data: {
            rightText: '登录',
            sendText: '',
            registerVisible: false,
            emojiVisible: false,
            contentHeight: document.body.clientHeight - 120 + 'px',
            myself: null,
            registerName: '',
            websocket: null,
            curSession: null,
            emoji: [
                {title: '笑嘻嘻', value: '😀'},
                {title: '笑嘻嘻的脸，含笑的眼睛', value: '😁'},
                {title: '脸上带着喜悦的泪水', value: '😂'},
                {title: '开口笑脸', value: '😃'},
                {title: '开口笑脸和微笑的眼睛', value: '😄'},
                {title: '笑脸淌冷汗', value: '😅'},
                {title: '开口笑紧闭的眼睛', value: '😆'},
                {title: '眨眼表情', value: '😉'},
                {title: '面带微笑的眼睛', value: '😊'},
                {title: '品尝美味食物表情', value: '😋'},
                {title: '太阳镜笑脸', value: '😎'},
                {title: '面带心形眼睛', value: '😍'},
                {title: '飞吻表情', value: '😘'},
                {title: '亲吻表情', value: '😗'},
                {title: '含笑亲吻表情', value: '😙'},
                {title: '闭眼亲吻表情', value: '😚'},
                {title: '光环笑脸', value: '😇'},
                {title: '中性面', value: '😐'},
                {title: '面无表情', value: '😑'},
                {title: '没有嘴的脸', value: '😶'},
                {title: '傻笑', value: '😏'},
                {title: '坚持', value: '😣'},
                {title: '失望得到宽慰的脸', value: '😥'},
                {title: '张着嘴', value: '😮'},
                {title: '安静的脸', value: '😯'},
                {title: '困', value: '😪'},
                {title: '疲惫', value: '😫'},
                {title: '熟睡', value: '😴'},
                {title: '安心', value: '😌'},
                {title: '吐舌头', value: '😛'},
                {title: '吐舌头，眨眼眼', value: '😜'},
                {title: '闭眼吐舌头', value: '😝'},
                {title: '垂头丧气', value: '😒'},
                {title: '冷汗', value: '😓'},
                {title: '沉思', value: '😔'},
                {title: '困惑', value: '😕'},
                {title: '惊讶', value: '😲'},
                {title: '戴口罩', value: '😷'},
                {title: '被打败', value: '😖'},
                {title: '失望', value: '😞'},
                {title: '忧伤', value: '😟'},
                {title: '面带胜利', value: '😤'},
                {title: '哭泣的脸', value: '😢'},
                {title: '大声哭泣的脸', value: '😭'},
                {title: '张嘴哭', value: '😦'},
                {title: '痛苦', value: '😧'},
                {title: '恐惧', value: '😨'},
                {title: '狰狞', value: '😬'},
                {title: '淌冷汗', value: '😰'},
                {title: '尖叫恐惧', value: '😱'},
                {title: '红扑扑的脸蛋', value: '😳'},
                {title: '晕', value: '😵'},
                {title: '噘嘴', value: '😡'},
                {title: '愤怒', value: '😠'},
                {title: '恶魔', value: '👿'},
            ],
            messages: []
        },
        methods: {
            onClickLeft() {
                // this.registerVisible = true;
            },
            onClickRight() {
                // vant.Toast('按钮');
            },
            showEmoji() {
                if (this.emojiVisible) {
                    this.emojiVisible = false;
                    this.contentHeight = document.body.clientHeight - 120 + 'px';
                } else {
                    this.emojiVisible = true;
                    this.contentHeight = document.body.clientHeight - 220 + 'px';
                }
            },
            hideEmoji() {
                if (this.emojiVisible) {
                    this.emojiVisible = false;
                    this.contentHeight = document.body.clientHeight - 120 + 'px';
                }
            },
            chooseEmoji(emoji) {
                this.sendText += emoji;
            },
            connectWebsocket() {
                if (!window.WebSocket) {
                    window.WebSocket = window.MozWebSocket;
                }
                this.websocket = new WebSocket(`ws://${window.location.host}/im/${this.myself.id}`);
                this.websocket.onmessage = event => this.onMessage(event);
                this.websocket.onopen = event => {
                    this.getPublicGroup();
                };
                this.websocket.onclose = event => {
                    console.error('关闭服务器连接!');
                };
                this.websocket.onerror = event => {
                    console.error('连接服务器失败!');
                };
            },
            register() {
                vant.Toast.loading({message: '加载中...', duration: 0});
                if (this.registerName.trim() === '') {
                    vant.Toast.fail({
                        message: '用户名为空',
                        onClose: () => {
                            this.registerVisible = true;
                        }
                    });
                    return;
                }
                axios.post('/im/register', {
                    name: this.registerName,
                    avatar: `${Math.round(Math.random() * 9)}.jpg`,
                    gender: 1
                }).then(response => {
                    if (response.data.code === 200) {
                        this.myself = response.data.data;
                        this.rightText = this.myself.name;
                        vant.Toast.loading('连接服务器...');
                        this.connectWebsocket();
                    }
                });
            },
            getPublicGroup() {
                axios.get('/im/getPublicGroup').then(response => {
                    if (response.data.code === 200) {
                        vant.Toast.loading('加入公共群...');
                        this.joinGroup(response.data.data[0]);
                    }
                });
            },
            joinGroup(group) {
                axios.post('/im/joinGroup', {groupId: group.id, userId: this.myself.id}).then(response => {
                    if (response.data.code === 200) {
                        const msg = {
                            fromId: this.myself.id,
                            fromName: this.myself.name,
                            toId: group.id,
                            toName: group.name,
                            type: 'TYPE_SYSTEM',
                            msgType: 'MSG_TYPE_JOIN',
                            content: `${this.myself.name} 加入了`
                        };
                        this.websocket.send(JSON.stringify(msg));
                        this.curSession = group;
                        this.getHistoryRecord();
                        vant.Toast.success('加入成功');
                    }
                });
            },
            getContacts() {
                axios.get(`/im/getContacts/${this.myself.id}`).then(response => {
                    if (response.data.code === 200) {

                    }
                });
            },
            getHistoryRecord() {
                axios.get(`/im/getHistoryRecord`, {
                    params: {
                        id: this.curSession.id,
                        type: 'group'
                    }
                }).then(async response => {
                    if (response.data.code === 200) {
                        response.data.data.forEach(v => {
                            v.content = this.dealContent(v.content);
                            v.sendTime = moment(v.sendTime).format('M-DD HH:mm:ss');
                        });
                        this.messages = response.data.data;
                        await this.$nextTick();
                        this.scrollTop();
                    }
                });
            },
            sendMsg() {
                if (this.sendText !== '') {
                    const msg = {
                        fromId: this.myself.id,
                        fromName: this.myself.name,
                        fromAvatar: this.myself.avatar,
                        toId: this.curSession.id,
                        toName: this.curSession.name,
                        toAvatar: this.curSession.avatar,
                        type: this.curSession.type === 'user' ? 'TYPE_ONE' : 'TYPE_GROUP',
                        msgType: 'text',
                        content: this.sendText,
                        time: null
                    };
                    this.websocket.send(JSON.stringify(msg));
                    this.sendText = '';
                }
            },
            scrollTop() {
                document.getElementById('chat_dialog').scrollTop = document.getElementById('chat_dialog').scrollHeight;
            },
            onMessage(event) {
                const imMessage = JSON.parse(event.data);
                switch (imMessage.type) {
                    case "TYPE_SYSTEM":
                    case "TYPE_GROUP":
                        imMessage.content = this.dealContent(imMessage.content);
                        imMessage.sendTime = moment(imMessage.sendTime).format('M-DD HH:mm:ss');
                        this.messages.push(imMessage);
                        this.$nextTick().then(() => {
                            this.scrollTop();
                        });
                        break;
                    case "TYPE_ONE":
                        break;
                }
            },
            dealContent(msg) {
                if (/^(\[FILE\]:)+[A-Za-z0-9]+:[\s\S]+.+[A-Za-z0-9]:[0-9]/.test(msg)) {
                    const str = msg.split(":");
                    return `<a target="_blank" href="im/download/${str[1]}" style="text-decoration: underline;">${str[2]} - ${(str[3] / 1024 / 1024).toFixed(2)}MB</a>`;
                } else if (/^(\[IMG\]:)+[A-Za-z0-9]/.test(msg)) {
                    const str = msg.split(":");
                    return `<img src="im/download/${str[1]}" style="max-width: 40vw;cursor: pointer;" onclick="window.open('im/download/${str[1]}')">`;
                } else {
                    return msg;
                }
            },
            uploadImg() {
                document.getElementById('imgFile').click();
            },
            imgChange() {
                if (document.getElementById('imgFile').files.length > 0) {
                    const formData = new FormData();
                    formData.append("file", document.getElementById('imgFile').files[0]);
                    axios.post('/im/upload', formData).then(response => {
                        if (response.data.code === 200) {
                            this.sendText = `[IMG]:${response.data.data.id}`;
                            this.sendMsg();
                            document.getElementById('imgFile').value = '';
                        }
                    });
                }
            }
        },
        created() {
            this.registerVisible = true;
        },
    });

    // 通过 CDN 引入时不会自动注册 Lazyload 组件
    // 可以通过下面的方式手动注册
    // Vue.use(vant.Lazyload);
</script>
</html>